/*
 * CollisionBlock.cpp
 *
 *  Created on: 2012-7-11
 *      Author: KamiyaSoft
 */

#include "KmyMath.h"
#include "KmyCollisionBlock.h"


KmyCollisionBlock::KmyCollisionBlock() {
	mask = 1;
	type = 0;
	X1 = -1;
	X2 = 1;
	Y1 = -1;
	Y2 = 1;
}

KmyCollisionBlock::KmyCollisionBlock(const KmyCollisionBlock* b, s32 x, s32 y){
	mask = b->mask;
	type = b->type;
	X1 = x+b->X1;
	X2 = x+b->X2;
	Y1 = y+b->Y1;
	Y2 = y+b->Y2;
}

bool KmyCollisionBlock::isTouchRRwithDeep(Point2D *deep,
		KmyCollisionBlock* block1, s32 x1, s32 y1,
		KmyCollisionBlock* block2, s32 x2, s32 y2){
	s32 p11 = MIN(x1+ block1->X1, x1+ block1->X2);
	s32 p12 = MAX(x1+ block1->X1, x1+ block1->X2);
	s32 p21 = MIN(x2+ block2->X1, x2+ block2->X2);
	s32 p22 = MAX(x2+ block2->X1, x2+ block2->X2);

	s32 x = MAX(0, MIN(p22-p11, p12-p21));

	p11 = MIN(y1+ block1->Y1, y1+ block1->Y2);
	p12 = MAX(y1+ block1->Y1, y1+ block1->Y2);
	p21 = MIN(y2+ block2->Y1, y2+ block2->Y2);
	p22 = MAX(y2+ block2->Y1, y2+ block2->Y2);

	s32 y = MAX(0, MIN(p22-p11, p12-p21));

	if (deep!=NULL){
		deep->x = x;
		deep->y = y;
	}
	if (x*y>0){
        return true;
	}else{
        return false;
	}
}

bool KmyCollisionBlock::isTouchBlock(const KmyCollisionBlock* b1, s32 x1, s32 y1,
	const KmyCollisionBlock* b2, s32 x2, s32 y2){
	KmyCollisionBlock block1(b1, x1, y1);
	KmyCollisionBlock block2(b2, x2, y2);
    if ((block1.mask & block2.mask) ==0){
        return false;
	}
	switch (block1.type){
	case CB_TYPE_RECTANGLE:
	{
		switch (block2.type){
		case CB_TYPE_RECTANGLE:
			return isTouchRR(&block1, 0, 0, &block2, 0, 0);
		case CB_TYPE_CIRCLE:
			//return isTouchRC(&block1, 0, 0, &block2, 0, 0);
			break;
		case CB_TYPE_LINE:
			return isTouchRL(&block1, 0, 0, &block2, 0, 0);
		}
	}
		break;
	case CB_TYPE_CIRCLE:
	{
		switch (block2.type){
		case CB_TYPE_RECTANGLE:
			//return isTouchRC(&block2, 0, 0, &block1, 0, 0);
			break;
		case CB_TYPE_CIRCLE:
			//return isTouchCC(&block1, 0, 0, &block2, 0, 0);
			break;
		case CB_TYPE_LINE:
			//return isTouchCL(&block1, 0, 0, &block2, 0, 0);
			break;
		}
	}
		break;
	case CB_TYPE_LINE:
	{
		switch (block2.type){
		case CB_TYPE_RECTANGLE:
			return isTouchRL(&block2, 0, 0, &block1, 0, 0);
		case CB_TYPE_CIRCLE:
			//return isTouchCL(&block2, 0, 0, &block1, 0, 0);
			break;
		case CB_TYPE_LINE:
			return isTouchLL(&block1, 0, 0, &block2, 0, 0);
		}
	}
		break;
//	case CB_TYPE_TRIANGLE:
//	{
//		switch (block2.type){
//		case CB_TYPE_RECTANGLE:
//			//return isTouchRT(&block2, 0, 0, &block1, 0, 0);
//			break;
//		case CB_TYPE_CIRCLE:
//			//return isTouchCT(&block2, 0, 0, &block1, 0, 0);
//			break;
//		case CB_TYPE_LINE:
//			//return isTouchLT(&block2, 0, 0, &block1, 0, 0);
//			break;
//		}
//	}
//		break;
	}
	return false;
}

bool KmyCollisionBlock::isTouchRR(const KmyCollisionBlock* block1, s32 x1, s32 y1,
		const KmyCollisionBlock* block2, s32 x2, s32 y2){
	s32 p11 = MIN(x1+ block1->X1, x1+ block1->X2);
	s32 p12 = MAX(x1+ block1->X1, x1+ block1->X2);
	s32 p21 = MIN(x2+ block2->X1, x2+ block2->X2);
	s32 p22 = MAX(x2+ block2->X1, x2+ block2->X2);

	s32 x = MAX(0, MIN(p22-p11, p12-p21));

	p11 = MIN(y1+ block1->Y1, y1+ block1->Y2);
	p12 = MAX(y1+ block1->Y1, y1+ block1->Y2);
	p21 = MIN(y2+ block2->Y1, y2+ block2->Y2);
	p22 = MAX(y2+ block2->Y1, y2+ block2->Y2);

	s32 y = MAX(0, MIN(p22-p11, p12-p21));

	if (x*y>0){
        return true;
	}else{
        return false;
	}
}

//bool KmyCollisionBlock::isTouchRC(const KmyCollisionBlock* block1, s32 x1, s32 y1,
//		const KmyCollisionBlock* block2, s32 x2, s32 y2){
//
//}

bool KmyCollisionBlock::isTouchRL(const KmyCollisionBlock* block1, s32 x1, s32 y1,
		const KmyCollisionBlock* block2, s32 x2, s32 y2){
	if (!isTouchRR(block1, x1, y1, block2, x2, y2)){
        return false;
	}
	KmyCollisionBlock tmpblock;
	tmpblock.type = CB_TYPE_LINE;
	tmpblock.X1 = block1->X1;
	tmpblock.Y1 = block1->Y1;
	tmpblock.X2 = block1->X2;
	tmpblock.Y2 = block1->Y1;
	if (isTouchLL(&tmpblock, x1, y1, block2, x2, y2)){
        return true;
	}
	tmpblock.X2 = block1->X1;
	tmpblock.Y2 = block1->Y2;
	if (isTouchLL(&tmpblock, x1, y1, block2, x2, y2)){
        return true;
	}
	tmpblock.X1 = block1->X2;
	tmpblock.Y1 = block1->Y2;
	if (isTouchLL(&tmpblock, x1, y1, block2, x2, y2)){
        return true;
	}
	tmpblock.X2 = block1->X2;
	tmpblock.Y2 = block1->Y1;
	if (isTouchLL(&tmpblock, x1, y1, block2, x2, y2)){
        return true;
	}
	return false;
}


//bool KmyCollisionBlock::isTouchCC(const KmyCollisionBlock* block1, s32 x1, s32 y1,
//		const KmyCollisionBlock* block2, s32 x2, s32 y2){
//
//}

//bool KmyCollisionBlock::isTouchCL(const KmyCollisionBlock* block1, s32 x1, s32 y1,
//		const KmyCollisionBlock* block2, s32 x2, s32 y2){
//
//}

bool KmyCollisionBlock::isTouchLL(const KmyCollisionBlock* block1, s32 x1, s32 y1,
		const KmyCollisionBlock* block2, s32 x2, s32 y2){
//    // 三角形abc 面积的2倍
//    var area_abc = (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x);
//
//    // 三角形abd 面积的2倍
//    var area_abd = (a.x - d.x) * (b.y - d.y) - (a.y - d.y) * (b.x - d.x);
//
//    // 面积符号相同则两点在线段同侧,不相交 (对点在线段上的情况,本例当作不相交处理);
//    if ( area_abc*area_abd>=0 ) {
//        return false;
//    }
//
//    // 三角形cda 面积的2倍
//    var area_cda = (c.x - a.x) * (d.y - a.y) - (c.y - a.y) * (d.x - a.x);
//    // 三角形cdb 面积的2倍
//    // 注意: 这里有一个小优化.不需要再用公式计算面积,而是通过已知的三个面积加减得出.
//    var area_cdb = area_cda + area_abc - area_abd ;
//    if (  area_cda * area_cdb >= 0 ) {
//        return false;
//    }
	s32 L1x1 = x1+block1->X1;
	s32 L1y1 = y1+block1->Y1;
	s32 L1x2 = x1+block1->X2;
	s32 L1y2 = y1+block1->Y2;
	s32 L2x1 = x2+block2->X1;
	s32 L2y1 = y2+block2->Y1;
	s32 L2x2 = x2+block2->X2;
	s32 L2y2 = y2+block2->Y2;
	int sabc = (L1x1 - L2x1)*(L1y2 - L2y1)
			- (L1y1 - L2y1)*(L1x2 - L2x1);
	int sabd = (L1x1 - L2x2)*(L1y2 - L2y2)
			- (L1y1 - L2y2)*(L1x2 - L2x2);
	if (sabc*sabd>=0){
        return false;
	}
	int scda = (L2x1 - L1x1)*(L2y2 - L1y1)
			- (L2y1 - L1y1)*(L2x2 - L1x1);
	int scdb = (L2x1 - L1x2)*(L2y2 - L1y2)
			- (L2y1 - L1y2)*(L2x2 - L1x2);
	if (scda*scdb>=0){
        return false;
	}

    return true;
}

